home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_77 / soundx.c < prev    next >
Text File  |  1995-01-01  |  7KB  |  365 lines

  1. /***************************************************************************** 
  2. *    Produces a code based on the "Soundex" method originally developed 
  3. *          by M.K. Odell and R.C. Russell.  Algorithm can be found on page 
  4. *          392 of Knuths' book 'Sorting and Searching', volume 3 of 'The Art 
  5. *          of Computer Programming", Addison/Wesley publisher. 
  6. *    Program Name: soundx.c  
  7. *    coded by:     Richard R. Schafer  
  8. *
  9. *********** RELEASED INTO THE PUBLIC DOMAIN *********************************/ 
  10.  
  11. #include "nandef.h" 
  12. #include "extend.h" 
  13.  
  14. #define ISALPHA(c)  ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') 
  15. #define UPPER(c)    ((c) >= 'a' && (c) <= 'z' ? (c) - 32 : (c)) 
  16.  
  17. #define CODE_ALLOC  5   /** size of code sequence.  4 for code 1 for NIL**/ 
  18.  
  19. CLIPPER soundx() 
  20.  
  21.      { 
  22.      /******************************************** 
  23.      *  the type_defs:   Boolean 
  24.      *                   quant 
  25.      *                   byte 
  26.      *  are defined in the include file "nandef.h" 
  27.      ********************************************/ 
  28.  
  29.      Boolean error; 
  30.  
  31.      quant i;        /*  Both 'i' and 'b' are counters  */ 
  32.      quant b; 
  33.      quant name_size; 
  34.  
  35.  
  36.      /*  'name' is where we put the parameter and 'short_name' is
  37.  
  38.      where we'll put the string that doesn't contain anything
  39.  
  40.      but ALPHA characters and 'code' is where we'll put the
  41.  
  42.      soundex code that we are developing.    */
  43.  
  44.      byte *name;
  45.  
  46.      byte *short_name;
  47.  
  48.      byte *code;
  49.  
  50.  
  51.  
  52.      /* intialize our code holder */
  53.      code = NULL;
  54.  
  55.  
  56.  
  57.      /* If any of these are true, we didn't get a proper parameter */
  58.  
  59.      error = (PCOUNT != 1 || !ISCHAR(1) || _parclen(1) == 0);
  60.  
  61.  
  62.  
  63.      /*  If we don't have any errors we'll continue otherwise dropout */
  64.  
  65.      if (!error)
  66.  
  67.           {
  68.  
  69.           /* put the parameter passed into an array */
  70.  
  71.           name = _parc(1);
  72.  
  73.  
  74.  
  75.           /* determine the length the of parameter passed
  76.  
  77.           and add 1 to hold the NIL byte
  78.  
  79.           */
  80.  
  81.           name_size = (quant) (_parclen(1) + 1);
  82.  
  83.  
  84.  
  85.           /*  Now that we've got something to work with, lets
  86.  
  87.           convert it to a soundex code.  First we have to
  88.  
  89.           allocate some memory for the code to be placed into.
  90.  
  91.           We'll use the function '_exmgrab' to do just that.
  92.  
  93.           */
  94.  
  95.           code = _exmgrab(CODE_ALLOC);
  96.  
  97.  
  98.  
  99.           /*  Now we'll initialize all of our arrays to hold NILs  */
  100.  
  101.           for (i = 0;i < name_size;i++)
  102.  
  103.                {
  104.  
  105.                short_name[i] = NIL;
  106.                }
  107.  
  108.  
  109.  
  110.           for (i = 0;i < CODE_ALLOC;i++)
  111.  
  112.                {
  113.  
  114.                code[i] = NIL;
  115.  
  116.                }
  117.  
  118.  
  119.  
  120.  
  121.  
  122.           /* now let's get rid of everything we don't want
  123.  
  124.           if it isn't an alpha character, we'll
  125.  
  126.           get rid of it and convert all else to uppercase
  127.  
  128.           */
  129.  
  130.           for (i = 0,b = 0;i < name_size; i++)
  131.  
  132.                {
  133.  
  134.                if (! ISALPHA(name[i]))
  135.  
  136.                     {
  137.  
  138.                     continue;
  139.  
  140.                     }
  141.  
  142.                /* if it is a good character we'll place it into
  143.  
  144.                another array to work from and increment the
  145.  
  146.                second counter 'b'            */
  147.  
  148.                short_name[b] = UPPER(name[i]);
  149.  
  150.                b++;
  151.  
  152.                }
  153.  
  154.  
  155.  
  156.           /*  The first character gets used as is */
  157.  
  158.           code[0] = short_name[0];
  159.  
  160.  
  161.           /*  Then we convert the rest of the string to the proper
  162.  
  163.           soundex numbers according to the algorithm.  We'll stay in
  164.  
  165.           the loop until such time as we have either run out of
  166.  
  167.           characters to work with, or we have filled the code.
  168.  
  169.           */
  170.  
  171.           for (i=1,b=1;(short_name[i] != NIL) && (b < (CODE_ALLOC - 1));i++ )
  172.  
  173.                {
  174.  
  175.                switch (short_name[i])
  176.  
  177.                     {
  178.  
  179.                     /*  These are the characters that we want to skip,
  180.  
  181.                     so if we match one we'll just go round for the
  182.  
  183.                     next character
  184.  
  185.                     */
  186.  
  187.                     case 'A':
  188.  
  189.                     case 'E':
  190.  
  191.                     case 'H':
  192.  
  193.                     case 'I':
  194.  
  195.                     case 'O':
  196.  
  197.                     case 'U':
  198.  
  199.                     case 'W':
  200.  
  201.                     case 'Y':
  202.  
  203.                          break;
  204.  
  205.  
  206.  
  207.                     /*  If we match any of these, they're the good ones
  208.  
  209.                     so we'll assign a number to 'code' for them.
  210.  
  211.                     */
  212.                     case 'B':
  213.  
  214.                     case 'F':
  215.  
  216.                     case 'P':
  217.  
  218.                     case 'V':
  219.  
  220.                          code[b] = '1';
  221.  
  222.                          b++;
  223.  
  224.                          break;
  225.  
  226.                     case 'C':
  227.  
  228.                     case 'G':
  229.  
  230.                     case 'J':
  231.  
  232.                     case 'K':
  233.  
  234.                     case 'Q':
  235.  
  236.                     case 'S':
  237.  
  238.                     case 'X':
  239.  
  240.                     case 'Z':
  241.  
  242.                          code[b] = '2';
  243.  
  244.                          b++;
  245.  
  246.                          break;
  247.  
  248.                     case 'D':
  249.  
  250.                     case 'T':                     code[b] = '3';
  251.  
  252.                          b++;
  253.  
  254.                          break;
  255.  
  256.                     case 'L':
  257.  
  258.                          code[b] = '4';
  259.  
  260.                          b++; 
  261.  
  262.                          break;
  263.  
  264.                     case 'M':
  265.                     case 'N':
  266.  
  267.                          code[b] = '5';
  268.  
  269.                          b++;
  270.  
  271.                          break;
  272.  
  273.                     case 'R':
  274.  
  275.                          code[b] = '6';
  276.  
  277.                          b++;
  278.  
  279.                          break;
  280.  
  281.                     }
  282.  
  283.  
  284.  
  285.                /*  If we haven't gone beyond the last character in
  286.  
  287.                'short_name'.
  288.  
  289.                */
  290.  
  291.                if (short_name[i + 1] != NIL)
  292.  
  293.                     {
  294.  
  295.  
  296.  
  297.                     /*  Check to see if the next character in the
  298.  
  299.                     array is the same as the one we just
  300.  
  301.                     evaluated, if so, we want to skip over it.
  302.  
  303.                     */
  304.  
  305.                     if (short_name[i] == short_name[i + 1])
  306.  
  307.                          {
  308.  
  309.                          i++;
  310.  
  311.                          }
  312.  
  313.                     }
  314.  
  315.                }
  316.  
  317.  
  318.           }
  319.  
  320.      
  321.  
  322.           /*  If the code isn't filled, we want to pad it with zeroes  */
  323.  
  324.           if (b < 4)
  325.  
  326.                {
  327.  
  328.                for (;b < 4;b++)
  329.  
  330.                     {
  331.  
  332.                     code[b] = '0';
  333.  
  334.                     }
  335.  
  336.                }
  337.  
  338.  
  339.  
  340.           /*  Now we setup to return the code and then release the memory
  341.  
  342.           that we allocated.  We'll use the "_exmback" function to do that.
  343.  
  344.           */
  345.  
  346.           if (!error)
  347.  
  348.                _retc(code);
  349.  
  350.           else
  351.  
  352.                _retc("");
  353.  
  354.      
  355.  
  356.           if (code)
  357.  
  358.                _exmback(code,CODE_ALLOC);
  359.  
  360.  
  361.  
  362.      }
  363.  
  364.